// 调度器
import { Dispatch } from 'react'
import {pop, push, peek, Task, Priority, priorityLevel} from './priority'

const tiemrQueue: Task[] = []
const taskQueue: Task[] = []

var initialTime = Date.now()

var taskIdCounter = 1
var taskTimeoutID: NodeJS.Timeout = -1 as unknown as NodeJS.Timeout
var isHostTimeouting = false

// 进去执行阶段
var isPerformingWork = false;

var isHostCallbackScheduled = false

var currentPriorityLevel: Priority = 'normal'

var isMessageLoopRunning = false
var scheduledHostCallback: any = null

var startTime = -1;

var currentTask: Task = {} as Task


var performWorkUntilDeadline = function() {
  if (scheduledHostCallback !== null) {
    var currentTime = getCurrentTime()
    startTime = currentTime
    var hasTimeRemaining = true

    var hasMoreWork = true

    try {
      hasMoreWork = scheduledHostCallback(hasTimeRemaining, currentTime)
    } finally {
      if (hasMoreWork) {
        schedulePerformWorkUntilDeadline()
      } else {
        isMessageLoopRunning = false
        scheduledHostCallback = null
      }
    }
  }
}


var schedulePerformWorkUntilDeadline: () => any

if (typeof setImmediate === 'function') {
  schedulePerformWorkUntilDeadline = () => {
    setImmediate(performWorkUntilDeadline)
  }
} else if (typeof MessageChannel !== 'undefined') {
  var channel = new MessageChannel();
  var port = channel.port2;
  channel.port1.onmessage = performWorkUntilDeadline;

  schedulePerformWorkUntilDeadline = function () {
    port.postMessage(null);
  };
} else {
  schedulePerformWorkUntilDeadline = () => {
    setTimeout(performWorkUntilDeadline, 0)
  }
}

// 什么时候，你怎么做，才能执行 taskQueue

export type ScheduleMapKey = 'delay' | 'cb' | 'debounce' | Dispatch<any>

export function scheduleTask(priority: Priority, map: Map<ScheduleMapKey, any>) {
  console.log('xxxxx schedule')
  var currentTime = getCurrentTime()
  var delay = map.get('delay')

  // 任务执行时间
  var startTime = delay > 0 ? currentTime + delay : currentTime

  var expirationTime = startTime + priorityLevel[priority]
  var callback = map.get('cb')

  var newTask: Task = {
    id: taskIdCounter++,
    priority: priority,
    startTime,
    expirationTime,
    cb: map.get('cb'),
    value: map.get(callback),
    sortIndex: -1
  }

  // 进入timerQueue
  if (startTime > currentTime) {
    newTask.sortIndex = startTime
    push(tiemrQueue, newTask)

    if (isHostTimeouting) {
      cancelHostTimeout()
    } else {
      isHostTimeouting = true
    }
    
    requestHostTimeout(handleTimeout, startTime - currentTime)
  } else {
    // 进去 taskQueue
    newTask.sortIndex = expirationTime
    var ft: Task = {} as Task
    taskQueue.forEach(task => {
      if (task.priority === newTask.priority && task.cb === newTask.cb) {
        ft = task
      }
    })
    // 先进入队列的任务，优先级更高
    // 新任务的值，有效性更强
    if (ft.id) {
      ft.value = newTask.value
    } else {
      push(taskQueue, newTask)
    }

    if (!isHostCallbackScheduled && !isPerformingWork) {
      isHostCallbackScheduled = true
      requestHostCallback(flushWork)
    }
  }
}

function advanceTimers(currentTime: number) {
  var timer = peek(tiemrQueue) as Task

  while(timer !== null) {
    if (timer.cb === null) {
      pop(tiemrQueue)
    } else if (timer.startTime <= currentTime) {
      pop(tiemrQueue)
      timer.sortIndex = timer.expirationTime
      var ft: Task = {} as Task
      taskQueue.forEach(task => {
        if (task.cb === timer.cb && task.priority === timer.priority) {
          ft = task
        }
      })
      if (ft.id) {
        ft.value = timer.value
      } else {
        push(taskQueue, timer)
      }
    } else {
      return
    } 

    timer = peek(tiemrQueue) as Task
  }
}

function getCurrentTime() {
  var hasPerformanceNow = typeof performance === 'object' && typeof performance.now === 'object'
  if (hasPerformanceNow) {
    return performance.now()
  }
  return Date.now() - initialTime
}

function requestHostTimeout(cb: (time: number) => any, ms: number) {
  taskTimeoutID = setTimeout(() => {
    cb(getCurrentTime())
  }, ms)
}

function cancelHostTimeout() {
  clearTimeout(taskTimeoutID)
  taskTimeoutID = -1 as any
}

function handleTimeout(currentTime: number) {
  isHostTimeouting = false
  advanceTimers(currentTime)

  if (!isHostCallbackScheduled) {
    if (peek(taskQueue) !== null) {
      isHostCallbackScheduled = true;
      requestHostCallback(flushWork);
    } else {
      var firstTimer = peek(tiemrQueue) as Task; 

      if (firstTimer !== null) {
        requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime);
      }
    }
  }
}

function requestHostCallback(callback: () => any) {
  scheduledHostCallback = callback
  if (!isMessageLoopRunning) {
    isMessageLoopRunning = true
    schedulePerformWorkUntilDeadline()
  }
}

function flushWork() {
  isHostCallbackScheduled = false
  if (isHostTimeouting) {
    isHostTimeouting = false
    cancelHostTimeout()
  }
  isPerformingWork = true
  var previousPriorityLevel = currentPriorityLevel;

  workLoop()

  currentTask = {} as Task
  currentPriorityLevel = previousPriorityLevel
  isPerformingWork = false
}

// setState -> DOM操作
// 放弃的意思是，最终不生成DOM操作

function workLoop() {
  var currentTime = initialTime
  advanceTimers(currentTime)
  currentTask = peek(taskQueue) as Task

  while(currentTask !== null) {
    
    if (currentTask.expirationTime > currentTime && shouldYieldToHost()) {
      break;
    }
    var callback = currentTask.cb
    if (typeof callback === 'function') {
      currentTask.cb = null as any
      currentPriorityLevel = currentTask.priority
      var didUserCallbackTimeout = currentTask.expirationTime <= currentTime;

      if (didUserCallbackTimeout) {
        callback(currentTask.value)
      }
      currentTime = getCurrentTime()

      if (currentTask === peek(taskQueue)) {
        pop(taskQueue)
      }

      advanceTimers(currentTime)
    } else {
      pop(taskQueue)
    }
    currentTask = peek(taskQueue) as Task
  }
}

function shouldYieldToHost() {
  var timeElapsed = getCurrentTime() - startTime;

  if (timeElapsed < 5) {
    // The main thread has only been blocked for a really short amount of time;
    // smaller than a single frame. Don't yield yet.
    return false;
  } // The main thread has been blocked for a non-negligible amount of time. We

  console.log('打断一次')

  return true;
}

// 初级  不让他的指令执行
function debounce() {
  let timer = null

  return function(...args: any) {

  }
}


// 专家 执行了，调度了，也进入 timerQueue 
